package com.hengpeng.itfin.service.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.hengpeng.common.exception.ServiceResult;
import com.hengpeng.common.exception.SystemException;
import com.hengpeng.common.persist.entity.AbstractEntity.BoolValue;
import com.hengpeng.common.util.DateTimeUtil;
import com.hengpeng.common.util.MoneyUtil;
import com.hengpeng.common.util.StringHelper;
import com.hengpeng.itfin.common.SystemConfigUtil;
import com.hengpeng.itfin.service.BorrowService;
import com.hengpeng.itfin.tools.InvestUtils;
import com.hengpeng.itfin.tools.JsonUtils;
import com.hengpeng.itfin.tools.New;
import com.hengpeng.itfin.tools.PoolServer;
import com.hengpeng.itfin.tools.StringUtils;
import com.hengpeng.itfinbase.constants.RespCodeConstants;
import com.hengpeng.itfinbase.constants.RespCodeConstants.BorrowInfoCode;
import com.hengpeng.itfinbase.constants.RespCodeConstants.CommonCode;
import com.hengpeng.itfinbase.constants.TransCodeConstants;
import com.hengpeng.itfinbase.en.ActivityType;
import com.hengpeng.itfinbase.en.BorrowStatus;
import com.hengpeng.itfinbase.en.DurationType;
import com.hengpeng.itfinbase.en.InputStatus;
import com.hengpeng.itfinbase.en.InvestStatus;
import com.hengpeng.itfinbase.en.SubAccountType;
import com.hengpeng.itfinbase.en.TradeMode;
import com.hengpeng.itfinbase.en.TransType;
import com.hengpeng.itfinbase.idAssign.ID;
import com.hengpeng.itfinbase.message.RequestMessage;
import com.hengpeng.itfinbase.message.ResponseMessage;
import com.hengpeng.itfinbase.message.activity.VipAddRateRequest;
import com.hengpeng.itfinbase.message.partner.AddBidInfoRequest;
import com.hengpeng.itfinbase.message.partner.DivDetail;
import com.hengpeng.itfinbase.message.partner.LoansRequest;
import com.hengpeng.itfinbase.message.partner.LoansResponse;
import com.hengpeng.itfinbase.message.partner.PartnerTransType;
import com.hengpeng.itfinbase.message.partner.ReconciliationRequestMsg;
import com.hengpeng.itfinbase.message.partner.ReconciliationResponseMsg;
import com.hengpeng.itfinbase.message.partner.ReconciliationResponseMsg.ReconciliationInfo;
import com.hengpeng.itfinbase.message.partner.UsrUnFreezeRequest;
import com.hengpeng.itfinbase.message.partner.UsrUnFreezeResponse;
import com.hengpeng.itfinbase.persist.Account;
import com.hengpeng.itfinbase.persist.BorrowInfo;
import com.hengpeng.itfinbase.persist.InvestInfo;
import com.hengpeng.itfinbase.persist.MessageTemplates;
import com.hengpeng.itfinbase.persist.Partner;
import com.hengpeng.itfinbase.persist.ReceivePlan;
import com.hengpeng.itfinbase.persist.ReceivePlan.ReceiveStatus;
import com.hengpeng.itfinbase.persist.RepaymentPlan;
import com.hengpeng.itfinbase.persist.RepaymentPlan.ReplaymentStatus;
import com.hengpeng.itfinbase.persist.SystemLog.LogType;

@Service
@Lazy
public class BorrowServiceImpl extends BaseServiceImpl implements BorrowService {
    public static Log logger = LogFactory.getLog(BorrowServiceImpl.class);

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int releaseBorrowMoney(Long borrowInfoId, Long rasieMoney, int raiseNum) {
        return serviceFactory.getDaoFactory().getBorrowInfoDao().releaseBorrowMoney(borrowInfoId, rasieMoney, raiseNum);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int releaseBorrowMoneyStatus(Long borrowInfoId, Long rasieMoney, int raiseNum, BorrowStatus newStatus) {
        return serviceFactory.getDaoFactory().getBorrowInfoDao()
                .releaseBorrowMoneyStatus(borrowInfoId, rasieMoney, raiseNum, newStatus);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void borrowStartRaise() {
        int i = daoFactory.getBorrowInfoDao().borrowStartRaise(BorrowStatus.RAISE, new Date(), BorrowStatus.SCHEDULED,
                new Date());
        logger.info("已处理" + i + "条标的为募集中");
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void borrowEndRaise() {
        int i = daoFactory.getBorrowInfoDao().borrowEndRaise(BorrowStatus.END, new Date(), BorrowStatus.RAISE,
                new Date());
        logger.info("已处理" + i + "条标的为募集结束");
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void overdure() {
        List<RepaymentPlan> plans = daoFactory.getRepaymentPlanDao().getOverdureList();
        for (RepaymentPlan plan : plans) {
            plan.setIsOverDured(BoolValue.YES);
            plan.setOverdueDate(DateTimeUtil.addDate(plan.getLastRepayDate(), 1));
            plan.setUpdateTime(new Date());
        }
        daoFactory.getRepaymentPlanDao().updatePlans(plans);
    }

    @Override
    public void addBidInfoList() {
        List<BorrowInfo> infoList = daoFactory.getBorrowInfoDao().getUnAddBidList();
        for (BorrowInfo borrow : infoList) {
            AddBidInfoRequest addRequest = new AddBidInfoRequest();
            addRequest.setBgRetUrl(service_notify_url);
            addRequest.setPartnerTransType(PartnerTransType.AddBidInfo);
            addRequest.setProId(borrow.getId().toString());
            addRequest.setBidStartDate(StringHelper.getStringFromDate(borrow.getBidOpenTime(), "yyyyMMddHHMMSS"));
            addRequest.setBidEndDate(StringHelper.getStringFromDate(borrow.getBidStopTime(), "yyyyMMddHHMMSS"));
            addRequest.setBorrCustId(borrow.getBorrowUserTrustAccountId());
            addRequest.setBorrTotAmt(MoneyUtil.convertFenToYuan(borrow.getBorrowMoney()));
            addRequest.setYearRate(new DecimalFormat("#.00").format((borrow.getBorrowRate() + borrow.getRewardRate())));
            addRequest.setGuarCompId(borrow.getGuaranteeUserTrustAccountId());
            Double guarAmt = borrow.getBorrowMoney() * borrow.getGuaranteeFeeRate() / 100;// 担保费用
            addRequest.setGuarAmt(MoneyUtil.convertFenToYuan(guarAmt.longValue()));
            addRequest.setProArea("4402");
            Date end = null;
            switch (borrow.getRepaymentType()) {
            case EQUALINTEREST:// 等额本息
                long month = InvestUtils.equalInterest(borrow.getBorrowMoney(),
                        (borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration());
                end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.MONTH);
                addRequest.setRetAmt(MoneyUtil.convertFenToYuan(month * borrow.getBorrowDuration()));
                addRequest.setRetDate(StringHelper.getStringFromDate(end, "yyyyMMdd"));
                addRequest.setRetType("01");
                break;
            case EQUALPRINCIPAL:// 等额本金
                long total = InvestUtils.equalPrincipal(borrow.getBorrowMoney(),
                        (borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration());// 等额本金还款总额
                end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.MONTH);
                addRequest.setRetAmt(MoneyUtil.convertFenToYuan(total));
                addRequest.setRetDate(StringHelper.getStringFromDate(end, "yyyyMMdd"));
                addRequest.setRetType("02");
                break;
            case MONTHINTEREST:// 按月付息到期还本
                if (borrow.getDurType().equals(DurationType.MONTH)) {
                    end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.MONTH);
                } else {
                    end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.DATE);
                }
                long interest = InvestUtils.rtcapitalInterest(borrow.getBorrowMoney(),
                        (borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration(),
                        borrow.getDurType());
                addRequest.setRetDate(StringHelper.getStringFromDate(end, "yyyyMMdd"));
                addRequest.setRetAmt(MoneyUtil.convertFenToYuan(interest + borrow.getBorrowMoney()));
                addRequest.setRetType("03");
                break;
            case RTCAPITALINTEREST:// 一次性还本付息
                if (borrow.getDurType().equals(DurationType.MONTH)) {
                    end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.MONTH);
                } else {
                    end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.DATE);
                }
                long rest = InvestUtils.rtcapitalInterest(borrow.getBorrowMoney(),
                        (borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration(),
                        borrow.getDurType());
                addRequest.setRetDate(StringHelper.getStringFromDate(end, "yyyyMMdd"));
                addRequest.setRetAmt(MoneyUtil.convertFenToYuan(rest + borrow.getBorrowMoney()));
                addRequest.setRetType("04");
                break;
            }
            serviceFactory.getBorrowService().addBidInfo(addRequest);
        }
    }

    @Override
    @Transactional(propagation = Propagation.NEVER)
    public ServiceResult<Boolean> loans(LoansRequest request) {
        final BorrowInfo borrow = daoFactory.getBorrowInfoDao().get(request.getBorrowId());
        serviceFactory.getBorrowService().makeReceivePlans(borrow);// 生成收款计划
        serviceFactory.getBorrowService().makeRepayPlans(borrow.getId());// 生成还款计划
        serviceFactory.getBorrowService().loansParnter(borrow, request);
        return new ServiceResult<Boolean>();
    }

    @Override
    public ServiceResult<Boolean> loss(UsrUnFreezeRequest request) {
        BorrowInfo borrow = daoFactory.getBorrowInfoDao().get(request.getBorrowId());
        List<InvestInfo> investList = daoFactory.getInvestInfoDao().queryList(borrow.getId(),
                new InvestStatus[] { InvestStatus.SUCESS, InvestStatus.CANCLING });
        if (investList != null && investList.size() > 0) {
            borrow.setStatus(BorrowStatus.LOSSING);
            serviceFactory.getPersistService().update(borrow);

            // PoolServer poolServer = new PoolServer(50);
            for (final InvestInfo invest : investList) {
                // poolServer.executeTask(new Runnable() {
                // public void run() {
                UsrUnFreezeRequest free = serviceFactory.getBorrowService().loss(invest);
                free.setBgRetUrl(request.getBgRetUrl());
                free.setRetUrl(request.getRetUrl());
                serviceFactory.getPartnerService().request(free);
                // try {
                // Thread.sleep(500);
                // } catch (Exception e) {
                // e.printStackTrace();
                // }
                // }
                // });
            }
            // poolServer.endServer();
        }

        return new ServiceResult<Boolean>();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public UsrUnFreezeRequest loss(InvestInfo invest) {
        InvestInfo info = daoFactory.getInvestInfoDao().get(invest.getId());

        UsrUnFreezeRequest request = new UsrUnFreezeRequest();

        String unFreeOrderId = ID.getInstanse().getID(18).toString();
        request.setOrdId(unFreeOrderId);
        request.setOrdDate(StringHelper.getStringFromDate(new Date(), "yyyyMMdd"));
        request.setTrxId(invest.getFreezeTrxId());
        request.setPartnerTransType(PartnerTransType.UsrUnFreeze);

        info.setStatus(InvestStatus.CANCLING);
        info.setUpdateTime(new Date());
        info.setUnFreeOderId(unFreeOrderId);

        daoFactory.getInvestInfoDao().update(info);
        return request;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public ServiceResult<String> lossResponse(UsrUnFreezeResponse response) {
        ServiceResult<String> result = new ServiceResult<String>();
        if (RespCodeConstants.CommonCode.TRANS_SUC.equals(response.getRespCode())) {
            InvestInfo investInfo = serviceFactory.getInvestInfoService().getInvestByUnFreeOrderId(response.getOrdId(),
                    false);
            if (investInfo != null && investInfo.getStatus().equals(InvestStatus.CANCLING)) {
                int i = daoFactory.getInvestInfoDao().cancel(response.getOrdId(), InvestStatus.CANCLING,
                        InvestStatus.CANCLED);
                if (i > 0) {
                    serviceFactory.getAccountService().changeAccountMoney(investInfo.getInvestUserId(),
                            investInfo.getInvestMoney(), 0l, 0l, 0l, TransType.CANCLE, TradeMode.UNFREEZE,
                            investInfo.getId().toString(), "标的撤标解冻:" + investInfo.getBorrowName());// 投资人解冻

                    // changeAccountMoney(investInfo.getInvestUserId(),
                    // investInfo.getInvestMoney(), null, null,
                    // TransType.CANCLE, TradeMode.UNFREEZE,
                    // investInfo.getId().toString(), "标的撤标解冻:" +
                    // investInfo.getBorrowName());// 投资人解冻
                    // 判断投标记录是否都已撤标,如果都已撤标则将借款标的状态改为:已流标
                    Long count = daoFactory.getInvestInfoDao().countByBorrowId(investInfo.getBorrowInfoId(),
                            new InvestStatus[] { InvestStatus.SUCESS, InvestStatus.CANCLING });
                    if (count == 0) {
                        BorrowInfo borrow = daoFactory.getBorrowInfoDao().get(investInfo.getBorrowInfoId());
                        borrow.setStatus(BorrowStatus.LOSSED);
                        daoFactory.getBorrowInfoDao().update(borrow);
                    }
                }
                result.setCode(RespCodeConstants.CommonCode.TRANS_SUC);
                result.setMessage(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
                result.setIsSuccess(true);
            } else {
                result.setCode(RespCodeConstants.InvestCode.INVEST_UNKONW);
                result.setMessage(RespCodeConstants.InvestCode.INVEST_UNKONW_MSG);
                result.setIsSuccess(false);
            }
        }
        return result;
    }

    @Override
    public ServiceResult<String> loansResponse(LoansResponse response) {
        ServiceResult<String> result = new ServiceResult<String>();
        if (response == null) {
            serviceFactory.getSystemLogService().addLog("", "", LogType.SYSTEMERROR, "汇付通知结果异常,返回结果为null");
        } else if (RespCodeConstants.CommonCode.TRANS_SUC.equals(response.getRespCode())
                || RespCodeConstants.BorrowInfoCode.TRANSMESSAGE_ERRCODE_LOANED.equals(response.getRespCode())) {
            InvestInfo investInfo = serviceFactory.getDaoFactory().getInvestInfoDao()
                    .get(Long.parseLong(response.getOrdId()));
            if (investInfo == null) {
                serviceFactory.getSystemLogService().addLog(
                        "",
                        response.getOrdId(),
                        LogType.SYSTEMERROR,
                        "放款异常：原投标订单缺失,汇付返回订单号：["
                                + (StringHelper.isEmpty(response.getOrdId()) ? "" : response.getOrdId()) + "]");
            } else if (investInfo.getStatus().equals(InvestStatus.LOANING)) {
                ReceivePlan plan = daoFactory.getStaticJDBCDao().getTotleReceive(investInfo.getId(),
                        investInfo.getInvestUserId());
                Long recBaseMoney = plan.getRecBaseMoney();
                Long recInterestMoney = plan.getRecInterestMoney();
                Long recAddMoney = plan.getRecAddMoney();

                // int i = serviceFactory.getDaoFactory().getInvestInfoDao()
                // .updateStatus(investInfo.getId(), InvestStatus.LOANING,
                // InvestStatus.LOANED);
                int i = serviceFactory.getInvestInfoService().updateStatus(investInfo.getId(), InvestStatus.LOANING,
                        InvestStatus.LOANED);
                if (i > 0) {
                    investInfo.setStatus(InvestStatus.LOANED);
                    BorrowInfo borrow = serviceFactory.getDaoFactory().getBorrowInfoDao()
                            .get(investInfo.getBorrowInfoId());

                    Long guaFee = InvestUtils
                            .accuracy(investInfo.getInvestMoney() * borrow.getGuaranteeFeeRate() / 100);// 保证金费率

                    Long fee = InvestUtils.accuracy(investInfo.getInvestMoney() * borrow.getBorrowFeeRate() / 100);// 平台佣金

                    Long borrowMoney = investInfo.getInvestMoney() - guaFee;// 借款人应收金额

                    /**
                     * 投资返利,启动返利
                     */
                    // int m = serviceFactory.getDaoFactory().getRebateDao()
                    // .activeByReferenceId(investInfo.getId().toString(), new
                    // Date());
                    int m = serviceFactory.getRebateService().activeByReferenceId(investInfo.getId().toString(),
                            new Date());
                    if (m <= 0) {
                        serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                                investInfo.getId().toString(), LogType.LOAN_EXCEPTION,
                                "放款成功启动返利更新数据为0，请查看返利是否已更新，还是根本返利记录为0");
                    }

                    /**
                     * 调用会员等级加息活动接口
                     */
                    VipAddRateRequest vipAddRateRequest = new VipAddRateRequest();
                    vipAddRateRequest.setActivityType(ActivityType.VIP_ADD_RATE);
                    vipAddRateRequest.setUserId(investInfo.getInvestUserId());
                    vipAddRateRequest.setBorrowInfoId(investInfo.getBorrowInfoId());
                    vipAddRateRequest.setInvestInfoId(investInfo.getId());
                    vipAddRateRequest.setInvestMoney(investInfo.getInvestMoney());
                    vipAddRateRequest.setTransType(TransCodeConstants.ActivityTransCode.VIP_ADD_RATE);
                    serviceFactory.getPortActiveFactory().remoteTrans(vipAddRateRequest);

                    serviceFactory.getAccountService().loansChangeAccountMoney(
                            investInfo.getInvestUserId(),
                            investInfo.getInvestMoney(),
                            recBaseMoney,
                            (recInterestMoney + recAddMoney),
                            TransType.LOAN,
                            TradeMode.SUBTRACT,
                            investInfo.getId().toString(),
                            "标的投资放款转出:" + investInfo.getInvestMoney() / 100 + ",解冻：" + investInfo.getInvestMoney()
                                    / 100, true);// 投资人投资解冻，放款转出

                    serviceFactory.getAccountService().loansChangeAccountMoney(borrow.getBorrowUserId(), borrowMoney,
                            recBaseMoney, recInterestMoney, TransType.LOAN, TradeMode.ADD,
                            investInfo.getId().toString(), "标的借款放款收入:" + borrow.getBorrowName(), true);// 借款人收入借款金额

                    if (guaFee > 0) {
                        serviceFactory.getAccountService().changeAccountMoney(borrow.getGuaranteeUserId(), guaFee, 0l,
                                0l, 0l, TransType.LOAN_GUAR, TradeMode.ADD, investInfo.getId().toString(),
                                "标的保证金放款收入:" + borrow.getBorrowName());// 保证金费率增加
                    }
                    if (fee > 0) {
                        serviceFactory.getAccountService().changeAccountMoney(borrow.getBorrowUserId(), fee, 0l, 0l,
                                0l, TransType.LOAN_FEE, TradeMode.SUBTRACT, borrow.getId().toString(),
                                "标的放款服务费扣款:" + borrow.getBorrowName());// 借款用户扣服务费证金
                    }
                    // 站内信 放款
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put("date", new Date());
                    map.put("money", MoneyUtil.convertFenToYuan(investInfo.getInvestMoney() == null ? 0 : investInfo
                            .getInvestMoney()));
                    serviceFactory.getMessageService().asynsendSystemMessageByTypeWithUsrCustId(
                            investInfo.getInvestUserTrustAccountId(), MessageTemplates.BusiType.M610.name(), map);

                    result.setCode(RespCodeConstants.CommonCode.TRANS_SUC);
                    result.setMessage("处理成功!");
                    result.setIsSuccess(true);
                } else {
                    serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                            investInfo.getId().toString(), LogType.LOAN_EXCEPTION,
                            "放款成功更新原投标状态失败,数据库更新状态失败，投标订单号[" + investInfo.getId() + "]");
                }
            } else {
                serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                        investInfo.getId().toString(), LogType.LOAN_MESSAGE,
                        "放款已处理,或原投标信息状态异常，当前标的状态[" + investInfo.getStatus() + "]");
                result.setCode("");
                result.setMessage("投资信息不存在或已经放款成功了");
                result.setIsSuccess(false);
            }
        }
        return result;
    }

    @Override
    public void loansParnter(final BorrowInfo borrow, final LoansRequest loansRequest) {
        List<InvestInfo> investList = daoFactory.getInvestInfoDao().queryList(borrow.getId(),
                new InvestStatus[] { InvestStatus.SUCESS, InvestStatus.LOANING });
        if (investList != null && investList.size() > 0) {
            // PoolServer poolServer = new PoolServer(50);
            for (final InvestInfo invest : investList) {
                // poolServer.executeTask(new Runnable() {
                // public void run() {
                LoansRequest request = serviceFactory.getBorrowService().loansInvest(borrow, invest);
                request.setBgRetUrl(loansRequest.getBgRetUrl());
                request.setRetUrl(loansRequest.getRetUrl());
                serviceFactory.getPartnerService().request(request);
                // try {
                // Thread.sleep(500);
                // } catch (Exception e) {
                // e.printStackTrace();
                // }
                // }
                // });
            }
            // poolServer.endServer();
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public LoansRequest loansInvest(BorrowInfo borrow, InvestInfo invest) {
        InvestInfo info = daoFactory.getInvestInfoDao().get(invest.getId());
        Long guarantFee = InvestUtils.accuracy(info.getInvestMoney() * borrow.getGuaranteeFeeRate() / 100);// 担保手续费
        Long fee = InvestUtils.accuracy(info.getInvestMoney() * borrow.getBorrowFeeRate() / 100);// 平台佣金

        LoansRequest request = new LoansRequest();
        request.setOrdId(info.getId().toString());
        request.setOrdDate(StringHelper.getStringFromDate(new Date(), "yyyyMMdd"));
        request.setOutCustId(info.getInvestUserTrustAccountId());
        request.setTransAmt(MoneyUtil.convertFenToYuan(info.getInvestMoney() - fee - guarantFee));
        request.setFee(MoneyUtil.convertFenToYuan(InvestUtils.accuracy(fee + guarantFee)));
        request.setSubOrdId(info.getId().toString());
        request.setSubOrdDate(StringHelper.getStringFromDate(info.getInvestTime(), "yyyyMMdd"));
        request.setInCustId(borrow.getBorrowUserTrustAccountId());
        if ((guarantFee != null && guarantFee > 0l) || (fee != null && fee > 0l)) {
            request.setFeeObjFlag("O");
        }
        request.setIsDefault("N");
        request.setIsUnFreeze("Y");
        request.setReqExt("{\"ProId\":\"" + borrow.getId() + "\"}");
        request.setFreezeTrxId(info.getFreezeTrxId());// 获取投标时汇付返回的冻结标识
        /** 生成解冻订单号 */
        String unFreezeOrdId = ID.getInstanse().getID(18).toString();
        request.setUnFreezeOrdId(unFreezeOrdId);
        info.setUnFreeOderId(unFreezeOrdId);

        request.setProId(borrow.getId().toString());
        request.setPartnerTransType(PartnerTransType.Loans);
        String partnerId = SystemConfigUtil.getConfigValue("partner.id");
        Partner partner = daoFactory.getPartnerDao().get(partnerId);
        String subAccountId = partner.getExtConfigs().get(SubAccountType.SPEDT.toString());
        Account guar = serviceFactory.getAccountService().getAccount(borrow.getGuaranteeUserId());
        if (guar == null) {
            throw new SystemException("放款失败，担保用户不存在:" + borrow.getGuaranteeUserId());
        }
        /**
         * <pre>
         * 分账：
         * (1)平台收取借款服务费
         * (2)担保人收取担保费
         * (3)手续费从借款人账户中扣取
         * </pre>
         */
        if ((guarantFee != null && guarantFee > 0l) || (fee != null && fee > 0l)) {
            List<DivDetail> divdetails = New.list();
            if (guarantFee > 0l) {
                DivDetail d = new DivDetail();
                d.setDivAcctId(guar.getSubAccountId());
                d.setDivAmt(MoneyUtil.convertFenToYuan(InvestUtils.accuracy(guarantFee)));
                d.setDivCustId(guar.getTrustAccountId());
                divdetails.add(d);
            }
            if (fee > 0l) {
                DivDetail d = new DivDetail();
                d.setDivAcctId(subAccountId);
                d.setDivAmt(MoneyUtil.convertFenToYuan(fee));
                d.setDivCustId(partner.getMerchantId());
                divdetails.add(d);
            }
            request.setDivDetails(JsonUtils.createGson().create().toJson(divdetails));
        }
        info.setStatus(InvestStatus.LOANING);
        info.setLoanTime(new Date());
        daoFactory.getInvestInfoDao().update(info);
        return request;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void makeRepayPlans(Long id) {
        BorrowInfo info = daoFactory.getBorrowInfoDao().lockById(id);
        List<RepaymentPlan> plans = new ArrayList<RepaymentPlan>();
        if (info.getStatus().equals(BorrowStatus.LOANING) || info.getStatus().equals(BorrowStatus.END)) {
            if (info.getIsMakeRepayPlan().equals(BoolValue.NO) && info.getIsMakeReceivePlan().equals(BoolValue.YES)) {
                getRepayPlans(info, plans);
                daoFactory.getRepaymentPlanDao().savePlans(plans);
                info.setLoanTime(new Date());
                info.setStatus(BorrowStatus.LOANING);
                info.setIsMakeRepayPlan(BoolValue.YES);
                daoFactory.getBorrowInfoDao().update(info);
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void makeReceivePlans(BorrowInfo borrow) {
        BorrowInfo borrowInfo = daoFactory.getBorrowInfoDao().lockById(borrow.getId());
        if (borrow.getStatus().equals(BorrowStatus.LOANING) || borrow.getStatus().equals(BorrowStatus.END)) {
            if (borrowInfo.getIsMakeReceivePlan().equals(BoolValue.NO)) {
                List<InvestInfo> investList = daoFactory.getInvestInfoDao().queryList(borrow.getId(),
                        new InvestStatus[] { InvestStatus.SUCESS, InvestStatus.LOANING });
                List<ReceivePlan> plans = new ArrayList<ReceivePlan>();
                for (InvestInfo invest : investList) {
                    getRecPlans(borrow, invest, plans);
                }
                serviceFactory.getPersistService().saveAllObject(plans);
                borrowInfo.setIsMakeReceivePlan(BoolValue.YES);
                daoFactory.getBorrowInfoDao().update(borrowInfo);
            }
        }
    }

    /**
     * <pre>
     * 生成还款计划
     * </pre>
     * 
     * @param borrow
     * @return
     */
    private List<ReceivePlan> getRecPlans(BorrowInfo borrow, InvestInfo invest, List<ReceivePlan> plans) {
        long monthMoney = 0;
        switch (borrow.getRepaymentType()) {
        case EQUALINTEREST:// 等额本息
            monthMoney = InvestUtils.equalInterest(invest.getInvestMoney(), borrow.getBorrowRate(),
                    borrow.getBorrowDuration());// 月还款额

            long monthRewardMoney = InvestUtils.equalInterest(invest.getInvestMoney(),
                    (borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration());// 加上附加利息的月收款总额

            Long[] monthBase = InvestUtils.equalInterestMonthBase(invest.getInvestMoney(), borrow.getBorrowRate(),
                    borrow.getBorrowDuration());// 月还款本金

            for (int i = 0; i < monthBase.length; i++) {
                ReceivePlan plan = new ReceivePlan();
                plan.setBorrowInfoId(borrow.getId());
                plan.setBorrowName(borrow.getBorrowName());
                plan.setCurRecNum((i + 1));
                plan.setCreateTime(new Date());
                plan.setInvestmentInfoId(invest.getId());
                plan.setInvestUserId(invest.getInvestUserId());
                plan.setInvestUserName(invest.getInvestUserName());
                plan.setInvestUserTrustAccountId(invest.getInvestUserTrustAccountId());

                plan.setRecBaseMoney(monthBase[i]);// 应收本金
                plan.setRecInterestMoney(monthMoney - monthBase[i]);// 应收利息
                plan.setRecMoney(monthRewardMoney);// 应收总金额
                plan.setRecAddMoney(monthRewardMoney - monthMoney);// 应收附加利息

                plan.setStatus(ReceiveStatus.WAITREC);
                plan.setTotalRecNum(monthBase.length);
                Date repayDate = StringUtils.addTime(new Date(), plan.getCurRecNum(), Calendar.MONTH);// 每期的最后还款日
                plan.setArrivalTime(DateTimeUtil.getSomeDayStartTimes(repayDate));
                plans.add(plan);
            }
            break;
        case EQUALPRINCIPAL:// 等额本金
            Long[] monthInterest = InvestUtils.equalPrincipalMonthInterest(invest.getInvestMoney(),
                    borrow.getBorrowRate(), borrow.getBorrowDuration());// 月收款利息
            Long[] monthAddInterest = InvestUtils.equalPrincipalMonthInterest(invest.getInvestMoney(),
                    borrow.getRewardRate(), borrow.getBorrowDuration());// 月收款附加利息
            Long monthBaseMoney = InvestUtils.accuracy(invest.getInvestMoney() / borrow.getBorrowDuration());// 每月应还本金
            Long totalMoney = 0L;
            for (int i = 0; i < monthInterest.length; i++) {
                Long recBase = monthBaseMoney;
                if (i == monthInterest.length - 1) {
                    recBase = invest.getInvestMoney() - totalMoney;
                } else {
                    totalMoney = totalMoney + recBase;
                }
                ReceivePlan plan = new ReceivePlan();
                plan.setBorrowInfoId(borrow.getId());
                plan.setBorrowName(borrow.getBorrowName());
                plan.setCurRecNum((i + 1));
                plan.setCreateTime(new Date());
                plan.setInvestmentInfoId(invest.getId());
                plan.setInvestUserId(invest.getInvestUserId());
                plan.setInvestUserName(invest.getInvestUserName());
                plan.setInvestUserTrustAccountId(invest.getInvestUserTrustAccountId());
                plan.setRecBaseMoney(recBase);
                plan.setRecInterestMoney(monthInterest[i]);
                plan.setRecAddMoney(monthAddInterest[i]);// 应收附加利息
                plan.setRecMoney(recBase + monthInterest[i] + monthAddInterest[i]);
                plan.setStatus(ReceiveStatus.WAITREC);
                plan.setTotalRecNum(monthInterest.length);
                Date repayDate = StringUtils.addTime(new Date(), plan.getCurRecNum(), Calendar.MONTH);// 每期的最后还款日
                plan.setArrivalTime(DateTimeUtil.getSomeDayStartTimes(repayDate));
                plans.add(plan);
            }
            break;
        case MONTHINTEREST:// 月付息
            for (int i = 1; i <= borrow.getBorrowDuration(); i++) {
                ReceivePlan plan = new ReceivePlan();
                plan.setBorrowInfoId(borrow.getId());
                plan.setBorrowName(borrow.getBorrowName());
                plan.setCurRecNum(i);
                plan.setCreateTime(new Date());
                plan.setInvestmentInfoId(invest.getId());
                plan.setInvestUserId(invest.getInvestUserId());
                plan.setInvestUserName(invest.getInvestUserName());
                plan.setInvestUserTrustAccountId(invest.getInvestUserTrustAccountId());

                long interest = InvestUtils.rtcapitalMonthInterest(invest.getInvestMoney(), borrow.getBorrowRate(),
                        borrow.getDurType());// 每月应还利息相等
                long add = InvestUtils.rtcapitalMonthInterest(invest.getInvestMoney(), borrow.getRewardRate(),
                        borrow.getDurType());// 每月应还附加利息
                plan.setRecBaseMoney(0L);
                if (i == borrow.getBorrowDuration()) {
                    plan.setRecBaseMoney(invest.getInvestMoney());
                }
                plan.setRecMoney(plan.getRecBaseMoney() + interest + add);// 应还总金额
                plan.setRecInterestMoney(interest);// 应还利息
                plan.setRecAddMoney(add);// 附加利息

                plan.setStatus(ReceiveStatus.WAITREC);
                plan.setTotalRecNum(borrow.getBorrowDuration());
                Date repayDate = StringUtils.addTime(new Date(), plan.getCurRecNum(), Calendar.MONTH);// 每期的最后还款日
                plan.setArrivalTime(DateTimeUtil.getSomeDayStartTimes(repayDate));
                plans.add(plan);
            }
            break;
        case RTCAPITALINTEREST:// 一次付
            ReceivePlan plan = new ReceivePlan();
            plan.setBorrowInfoId(borrow.getId());
            plan.setBorrowName(borrow.getBorrowName());
            plan.setCurRecNum(1);
            plan.setCreateTime(new Date());
            plan.setInvestmentInfoId(invest.getId());
            plan.setInvestUserId(invest.getInvestUserId());
            plan.setInvestUserName(invest.getInvestUserName());
            plan.setInvestUserTrustAccountId(invest.getInvestUserTrustAccountId());
            long interest = InvestUtils.rtcapitalInterest(invest.getInvestMoney(), borrow.getBorrowRate(),
                    borrow.getBorrowDuration(), borrow.getDurType());
            long add = InvestUtils.rtcapitalInterest(invest.getInvestMoney(), borrow.getRewardRate(),
                    borrow.getBorrowDuration(), borrow.getDurType());// 附加利息
            plan.setRecBaseMoney(invest.getInvestMoney());
            plan.setRecAddMoney(add);// 附加利息
            plan.setRecInterestMoney(interest);// 应还利息
            plan.setRecMoney(invest.getInvestMoney() + interest + add);// 应还总金额
            plan.setStatus(ReceiveStatus.WAITREC);
            plan.setTotalRecNum(1);
            int type = Calendar.MONTH;
            if (!borrow.getDurType().equals(DurationType.MONTH)) {
                type = Calendar.DATE;
            }
            Date repayDate = StringUtils.addTime(new Date(), borrow.getBorrowDuration(), type);// 每期的最后还款日
            plan.setArrivalTime(DateTimeUtil.getSomeDayStartTimes(repayDate));
            plans.add(plan);
            break;
        }
        return plans;
    }

    /**
     * <pre>
     * 生成还款计划
     * </pre>
     * 
     * @param borrow
     * @return
     */
    private void getRepayPlans(BorrowInfo borrow, List<RepaymentPlan> plans) {
        List<ReceivePlan> planList = daoFactory.getStaticJDBCDao().getTotleList(borrow.getId());
        for (ReceivePlan receivePlan : planList) {
            RepaymentPlan plan = new RepaymentPlan();
            plan.setBorrowInfoId(borrow.getId());
            plan.setBorrowName(borrow.getBorrowName());
            plan.setBorrowUserId(borrow.getBorrowUserId());
            plan.setBorrowUserName(borrow.getBorrowUserName());
            plan.setCreateTime(new Date());
            plan.setCurRepayNum(receivePlan.getCurRecNum());
            plan.setIsOverDured(BoolValue.NO);
            plan.setLastRepayDate(receivePlan.getArrivalTime());
            plan.setOverdueDate(DateTimeUtil.addDate(plan.getLastRepayDate(), 1));// 逾期起息日，为最后还款日的下一天
            plan.setOverduePenalty(0L);
            plan.setRepayAddMoney(receivePlan.getRecAddMoney());// 应还附加利息(由平台账户付款)
            plan.setRepayBaseMoney(receivePlan.getRecBaseMoney());// 应还本金
            plan.setRepayMoney(receivePlan.getRecMoney());// 应还总金额
            plan.setRepayInterestMoney(receivePlan.getRecInterestMoney());// 应还利息
            plan.setStatus(ReplaymentStatus.UNSETTLE);
            plan.setTotalRepayNum(receivePlan.getTotalRecNum());
            plans.add(plan);
        }
    }

    /**
     * <pre>
     * 标的信息录入
     * </pre>
     * 
     * @param request
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public ResponseMessage addBidInfo(RequestMessage request) {
        ResponseMessage response = null;
        AddBidInfoRequest addRequest = (AddBidInfoRequest) request;
        Long borowId = Long.parseLong(addRequest.getProId());
        BorrowInfo borrow = daoFactory.getBorrowInfoDao().get(borowId);
        if (borrow != null) {
            if (borrow.getInputStatus() == InputStatus.WAIT || borrow.getInputStatus() == InputStatus.FAILED) {
                response = serviceFactory.getPartnerService().request(request);
                if (CommonCode.TRANS_SUC.equals(response.getRespCode())
                        || BorrowInfoCode.TRANSMESSAGE_ERRCODE_ADDBID_EXIST.equals(response.getRespCode())) {
                    daoFactory.getBorrowInfoDao().updateInputStatus(InputStatus.SUCCESS, new Date(), borrow.getId(),
                            InputStatus.WAIT, InputStatus.FAILED);
                }
            }
        }
        return response;
    }

    @Override
    public void borrowLoanEnd() {
        List<BorrowInfo> list = daoFactory.getBorrowInfoDao().queryBorrowList(BorrowStatus.LOANING);
        for (BorrowInfo borrowInfo : list) {
            serviceFactory.getBorrowService().requireNewLoanEnd(borrowInfo);
        }
    }

    @Override
    public void borrowLossEnd() {
        List<BorrowInfo> list = daoFactory.getBorrowInfoDao().queryBorrowList(BorrowStatus.LOSSING);
        for (BorrowInfo borrowInfo : list) {
            serviceFactory.getBorrowService().requireNewLoanEnd(borrowInfo);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void requireNewLossEnd(BorrowInfo borrowInfo) {
        BorrowInfo borrow = daoFactory.getBorrowInfoDao().lockById(borrowInfo.getId());
        if (borrow.getStatus().equals(BorrowStatus.LOANING)) {
            InvestStatus[] status = new InvestStatus[] { InvestStatus.CANCLED, InvestStatus.SUCESS,
                    InvestStatus.CANCLING };
            long count = daoFactory.getInvestInfoDao().countByBorrowId(borrow.getId(), status);
            long cancled = daoFactory.getInvestInfoDao().countByBorrowId(borrow.getId(),
                    new InvestStatus[] { InvestStatus.CANCLED });
            if (count == cancled) {
                borrow.setStatus(BorrowStatus.LOSSED);
            }
            daoFactory.getBorrowInfoDao().update(borrow);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void requireNewLoanEnd(BorrowInfo borrowInfo) {
        BorrowInfo borrow = daoFactory.getBorrowInfoDao().get(borrowInfo.getId());
        if (borrow.getStatus().equals(BorrowStatus.LOANING)) {
            InvestStatus[] status = new InvestStatus[] { InvestStatus.LOANED, InvestStatus.SUCESS, InvestStatus.LOANING };
            long count = daoFactory.getInvestInfoDao().countByBorrowId(borrow.getId(), status);
            long loaned = daoFactory.getInvestInfoDao().countByBorrowId(borrow.getId(),
                    new InvestStatus[] { InvestStatus.LOANED });
            if (count == loaned) {
                daoFactory.getBorrowInfoDao().updateStatus(borrowInfo.getId(), BorrowStatus.REPAYMENTING,
                        BorrowStatus.LOANING, new Date(), null);
            }
        }
    }

    @Override
    public void loansReconciliation(Integer pageNum, Integer pageSize, Date beginDate, Date endDate) {
        ReconciliationResponseMsg response = serviceFactory.getBorrowService().doLoansReconciliation(pageNum, pageSize,
                beginDate, endDate);
        if (!StringHelper.isEmpty(response.getTotalItems())
                && (pageNum * pageSize) < Integer.parseInt(response.getTotalItems())) {
            loansReconciliation(pageNum + 1, pageSize, beginDate, endDate);
        }
    }

    @Override
    public ReconciliationResponseMsg doLoansReconciliation(Integer pageNum, Integer pageSize, Date beginDate,
            Date endDate) {
        ReconciliationRequestMsg reqMsg = new ReconciliationRequestMsg();
        reqMsg.setBeginDate(DateTimeUtil.formatToStr(beginDate, DateTimeUtil.DATE_FORMAT_YYYYMMDD));
        reqMsg.setEndDate(DateTimeUtil.formatToStr(endDate, DateTimeUtil.DATE_FORMAT_YYYYMMDD));
        reqMsg.setPageNum(pageNum.toString());
        reqMsg.setPageSize(pageSize.toString());
        reqMsg.setQueryTransType("LOANS");
        reqMsg.setPartnerTransType(PartnerTransType.Reconciliation);
        reqMsg.setTransType(TransCodeConstants.PartnerTransCode.REQUEST);
        ReconciliationResponseMsg response = (ReconciliationResponseMsg) serviceFactory.getPartnerService().request(
                reqMsg);
        List<ReconciliationInfo> list = response.getReconciliationDtoList();
        if (list != null && list.size() > 0) {
            // PoolServer poolServer = new PoolServer(50);
            for (ReconciliationInfo dto : list) {
                final LoansResponse loansResponse = new LoansResponse();
                loansResponse.setOrdId(dto.getOrdId());
                if ("I".equals(dto.getTransStat()) || "P".equals(dto.getTransStat())) {
                    if ("I".equals(dto.getTransStat())) {// 失败
                        loansResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_FAIL);
                        loansResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_FAIL_MSG);
                    } else if ("P".equals(dto.getTransStat())) {// 成功
                        loansResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_SUC);
                        loansResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
                    }
                    serviceFactory.getBorrowService().loansResponse(loansResponse);
                }
                // poolServer.executeTask(new Runnable() {
                // @Override
                // public void run() {
                // serviceFactory.getBorrowService().loansResponse(loansResponse);
                // }
                // });
            }
            // poolServer.endServer();
        }
        return response;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int updateBorroInoStatus(Long borrowInoId, BorrowStatus newStatus, BorrowStatus oldStatus, Date updatTime,
            Date repaymentedTime) {
        return serviceFactory
                .getDaoFactory()
                .getBorrowInfoDao()
                .updateStatus(borrowInoId, BorrowStatus.REPAYMENTED, BorrowStatus.REPAYMENTING, updatTime,
                        repaymentedTime);
    }

}